home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / ex_vops.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-24  |  18.7 KB  |  948 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)ex_vops.c    7.8 (Berkeley) 3/9/87; 1.2 (Bellcore)    87/04/24";
  9. #endif not lint
  10.  
  11. #include "ex.h"
  12. #include "ex_tty.h"
  13. #include "ex_vis.h"
  14.  
  15. /*
  16.  * This file defines the operation sequences which interface the
  17.  * logical changes to the file buffer with the internal and external
  18.  * display representations.
  19.  */
  20.  
  21. /*
  22.  * Undo.
  23.  *
  24.  * Undo is accomplished in two ways.  We often for small changes in the
  25.  * current line know how (in terms of a change operator) how the change
  26.  * occurred.  Thus on an intelligent terminal we can undo the operation
  27.  * by another such operation, using insert and delete character
  28.  * stuff.  The pointers vU[AD][12] index the buffer vutmp when this
  29.  * is possible and provide the necessary information.
  30.  *
  31.  * The other case is that the change involved multiple lines or that
  32.  * we have moved away from the line or forgotten how the change was
  33.  * accomplished.  In this case we do a redisplay and hope that the
  34.  * low level optimization routines (which don't look for winning
  35.  * via insert/delete character) will not lose too badly.
  36.  */
  37. char    *vUA1, *vUA2;
  38. char    *vUD1, *vUD2;
  39.  
  40. ex_vUndo()
  41. {
  42.  
  43.     /*
  44.      * Avoid UU which clobbers ability to do u.
  45.      */
  46.     if (vundkind == VCAPU || vUNDdot != dot) {
  47.         beep();
  48.         return;
  49.     }
  50.     CP(vutmp, linebuf);
  51.     vUD1 = linebuf; vUD2 = strend(linebuf);
  52.     putmk1(dot, vUNDsav);
  53.     getDOT();
  54.     vUA1 = linebuf; vUA2 = strend(linebuf);
  55.     vundkind = VCAPU;
  56.     if (state == ONEOPEN || state == HARDOPEN) {
  57.         vjumpto(dot, vUNDcurs, 0);
  58.         return;
  59.     }
  60.     vdirty(vcline, 1);
  61.     vsyncCL();
  62.     cursor = linebuf;
  63.     vfixcurs();
  64. }
  65.  
  66. vundo(show)
  67. bool show;    /* if true update the screen */
  68. {
  69.     register int cnt;
  70.     register line *addr;
  71.     register char *cp;
  72.     char temp[LBSIZE];
  73.     bool savenote;
  74.     int (*OO)();
  75.     short oldhold = hold;
  76.  
  77.     switch (vundkind) {
  78.  
  79.     case VMANYINS:
  80.         wcursor = 0;
  81.         addr1 = undap1;
  82.         addr2 = undap2 - 1;
  83.         vsave();
  84.         YANKreg('1');
  85.         notecnt = 0;
  86.         /* fall into ... */
  87.  
  88.     case VMANY:
  89.     case VMCHNG:
  90.         vsave();
  91.         addr = dot - vcline;
  92.         notecnt = 1;
  93.         if (undkind == UNDPUT && undap1 == undap2) {
  94.             beep();
  95.             break;
  96.         }
  97.         /*
  98.          * Undo() call below basically replaces undap1 to undap2-1
  99.          * with dol through unddol-1.  Hack screen image to
  100.          * reflect this replacement.
  101.          */
  102.         if (show)
  103.             if (undkind == UNDMOVE)
  104.                 vdirty(0, LINES);
  105.             else
  106.                 vreplace(undap1 - addr, undap2 - undap1,
  107.                     undkind == UNDPUT ? 0 : unddol - dol);
  108.         savenote = notecnt;
  109.         undo(1);
  110.         if (show && (vundkind != VMCHNG || addr != dot))
  111.             killU();
  112.         vundkind = VMANY;
  113.         cnt = dot - addr;
  114.         if (cnt < 0 || cnt > vcnt || state != VISUAL) {
  115.             if (show)
  116.                 vjumpto(dot, NOSTR, '.');
  117.             break;
  118.         }
  119.         if (!savenote)
  120.             notecnt = 0;
  121.         if (show) {
  122.             vcline = cnt;
  123.             vrepaint(vmcurs);
  124.         }
  125.         vmcurs = 0;
  126.         break;
  127.  
  128.     case VCHNG:
  129.     case VCAPU:
  130.         vundkind = VCHNG;
  131.         strcpy(temp, vutmp);
  132.         strcpy(vutmp, linebuf);
  133.         doomed = column(vUA2 - 1) - column(vUA1 - 1);
  134.         strcLIN(temp);
  135.         cp = vUA1; vUA1 = vUD1; vUD1 = cp;
  136.         cp = vUA2; vUA2 = vUD2; vUD2 = cp;
  137.         if (!show)
  138.             break;
  139.         cursor = vUD1;
  140.         if (state == HARDOPEN) {
  141.             doomed = 0;
  142.             vsave();
  143.             vopen(dot, WBOT);
  144.             vnline(cursor);
  145.             break;
  146.         }
  147.         /*
  148.          * Pseudo insert command.
  149.          */
  150.         vcursat(cursor);
  151.         OO = Outchar; Outchar = vinschar; hold |= HOLDQIK;
  152.         vprepins();
  153.         temp[vUA2 - linebuf] = 0;
  154.         for (cp = &temp[vUA1 - linebuf]; *cp;)
  155.             ex_putchar(*cp++);
  156.         Outchar = OO; hold = oldhold;
  157.         endim();
  158.         physdc(cindent(), cindent() + doomed);
  159.         doomed = 0;
  160.         vdirty(vcline, 1);
  161.         vsyncCL();
  162.         if (cursor > linebuf && cursor >= strend(linebuf))
  163.             cursor--;
  164.         vfixcurs();
  165.         break;
  166.  
  167.     case VNONE:
  168.         beep();
  169.         break;
  170.     }
  171. }
  172.  
  173. /*
  174.  * Routine to handle a change inside a macro.
  175.  * Fromvis is true if we were called from a visual command (as
  176.  * opposed to an ex command).  This has nothing to do with being
  177.  * in open/visual mode as :s/foo/bar is not fromvis.
  178.  */
  179. vmacchng(fromvis)
  180. bool fromvis;
  181. {
  182.     line *savedot, *savedol;
  183.     char *savecursor;
  184.     char savelb[LBSIZE];
  185.     int nlines, more;
  186.     int copyw(), copywR();
  187.  
  188.     if (!inopen)
  189.         return;
  190.     if (!vmacp)
  191.         vch_mac = VC_NOTINMAC;
  192. #ifdef TRACE
  193.     if (trace)
  194.         fprintf(trace, "vmacchng, vch_mac=%d, linebuf='%s', *dot=%o\n", vch_mac, linebuf, *dot);
  195. #endif
  196.     if (vmacp && fromvis)
  197.         vsave();
  198. #ifdef TRACE
  199.     if (trace)
  200.         fprintf(trace, "after vsave, linebuf='%s', *dot=%o\n", linebuf, *dot);
  201. #endif
  202.     switch(vch_mac) {
  203.     case VC_NOCHANGE:
  204.         vch_mac = VC_ONECHANGE;
  205.         break;
  206.     case VC_ONECHANGE:
  207.         /* Save current state somewhere */
  208. #ifdef TRACE
  209.         vudump("before vmacchng hairy case");
  210. #endif
  211.         savedot = dot; savedol = dol; savecursor = cursor;
  212.         CP(savelb, linebuf);
  213.         nlines = dol - zero;
  214.         while ((line *) endcore - truedol < nlines)
  215.             if (morelines() < 0) {
  216.                 dot = savedot;
  217.                 dol = savedol;
  218.                 cursor = savecursor;
  219.                 CP(linebuf, savelb);
  220.                 error("Out of memory@- too many lines to undo");
  221.             }
  222.         copyw(truedol+1, zero+1, nlines);
  223.         truedol += nlines;
  224.  
  225. #ifdef TRACE
  226.         visdump("before vundo");
  227. #endif
  228.         /* Restore state as it was at beginning of macro */
  229.         vundo(0);
  230. #ifdef TRACE
  231.         visdump("after vundo");
  232.         vudump("after vundo");
  233. #endif
  234.  
  235.         /* Do the saveall we should have done then */
  236.         saveall();
  237. #ifdef TRACE
  238.         vudump("after saveall");
  239. #endif
  240.  
  241.         /* Restore current state from where saved */
  242.         more = savedol - dol; /* amount we shift everything by */
  243.         if (more)
  244.             (*(more>0 ? copywR : copyw))(savedol+1, dol+1, truedol-dol);
  245.         unddol += more; truedol += more; undap2 += more;
  246.  
  247.         truedol -= nlines;
  248.         copyw(zero+1, truedol+1, nlines);
  249.         dot = savedot; dol = savedol ; cursor = savecursor;
  250.         CP(linebuf, savelb);
  251.         vch_mac = VC_MANYCHANGE;
  252.  
  253.         /* Arrange that no further undo saving happens within macro */
  254.         otchng = tchng;    /* Copied this line blindly - bug? */
  255.         inopen = -1;    /* no need to save since it had to be 1 or -1 before */
  256.         vundkind = VMANY;
  257. #ifdef TRACE
  258.         vudump("after vmacchng");
  259. #endif
  260.         break;
  261.     case VC_NOTINMAC:
  262.     case VC_MANYCHANGE:
  263.         /* Nothing to do for various reasons. */
  264.         break;
  265.     }
  266. }
  267.  
  268. /*
  269.  * Initialize undo information before an append.
  270.  */
  271. vnoapp()
  272. {
  273.  
  274.     vUD1 = vUD2 = cursor;
  275. }
  276.  
  277. /*
  278.  * All the rest of the motion sequences have one or more
  279.  * cases to deal with.  In the case wdot == 0, operation
  280.  * is totally within current line, from cursor to wcursor.
  281.  * If wdot is given, but wcursor is 0, then operation affects
  282.  * the inclusive line range.  The hardest case is when both wdot
  283.  * and wcursor are given, then operation affects from line dot at
  284.  * cursor to line wdot at wcursor.
  285.  */
  286.  
  287. /*
  288.  * Move is simple, except for moving onto new lines in hardcopy open mode.
  289.  */
  290. vmove()
  291. {
  292.     register int cnt;
  293.  
  294.     if (wdot) {
  295.         if (wdot < one || wdot > dol) {
  296.             beep();
  297.             return;
  298.         }
  299.         cnt = wdot - dot;
  300.         wdot = NOLINE;
  301.         if (cnt)
  302.             killU();
  303.         vupdown(cnt, wcursor);
  304.         return;
  305.     }
  306.  
  307.     /*
  308.      * When we move onto a new line, save information for U undo.
  309.      */
  310.     if (vUNDdot != dot) {
  311.         vUNDsav = *dot;
  312.         vUNDcurs = wcursor;
  313.         vUNDdot = dot;
  314.     }
  315.  
  316.     /*
  317.      * In hardcopy open, type characters to left of cursor
  318.      * on new line, or back cursor up if its to left of where we are.
  319.      * In any case if the current line is ``rubbled'' i.e. has trashy
  320.      * looking overstrikes on it or \'s from deletes, we reprint
  321.      * so it is more comprehensible (and also because we can't work
  322.      * if we let it get more out of sync since column() won't work right.
  323.      */
  324.     if (state == HARDOPEN) {
  325.         register char *cp;
  326.         if (rubble) {
  327.             register int c;
  328.             int oldhold = hold;
  329.  
  330.             sethard();
  331.             cp = wcursor;
  332.             c = *cp;
  333.             *cp = 0;
  334.             hold |= HOLDDOL;
  335.             ignore(vreopen(WTOP, lineDOT(), vcline));
  336.             hold = oldhold;
  337.             *cp = c;
  338.         } else if (wcursor > cursor) {
  339.             vfixcurs();
  340.             for (cp = cursor; *cp && cp < wcursor;) {
  341.                 register int c = *cp++ & TRIM;
  342.  
  343.                 ex_putchar(c ? c : ' ');
  344.             }
  345.         }
  346.     }
  347.     vsetcurs(wcursor);
  348. }
  349.  
  350. /*
  351.  * Delete operator.
  352.  *
  353.  * Hard case of deleting a range where both wcursor and wdot
  354.  * are specified is treated as a special case of change and handled
  355.  * by vchange (although vchange may pass it back if it degenerates
  356.  * to a full line range delete.)
  357.  */
  358. vdelete(c)
  359.     char c;
  360. {
  361.     register char *cp;
  362.     register int i;
  363.  
  364.     if (wdot) {
  365.         if (wcursor) {
  366.             vchange('d');
  367.             return;
  368.         }
  369.         if ((i = xdw()) < 0)
  370.             return;
  371.         if (state != VISUAL) {
  372.             vgoto(LINE(0), 0);
  373.             vputchar('@');
  374.         }
  375.         wdot = dot;
  376.         vremote(i, ex_delete, 0);
  377.         notenam = "delete";
  378.         DEL[0] = 0;
  379.         killU();
  380.         vreplace(vcline, i, 0);
  381.         if (wdot > dol)
  382.             vcline--;
  383.         vrepaint(NOSTR);
  384.         return;
  385.     }
  386.     if (wcursor < linebuf)
  387.         wcursor = linebuf;
  388.     if (cursor == wcursor) {
  389.         beep();
  390.         return;
  391.     }
  392.     i = vdcMID();
  393.     cp = cursor;
  394.     setDEL();
  395.     CP(cp, wcursor);
  396.     if (cp > linebuf && (cp[0] == 0 || c == '#'))
  397.         cp--;
  398.     if (state == HARDOPEN) {
  399.         bleep(i, cp);
  400.         cursor = cp;
  401.         return;
  402.     }
  403.     physdc(column(cursor - 1), i);
  404.     DEPTH(vcline) = 0;
  405.     ignore(vreopen(LINE(vcline), lineDOT(), vcline));
  406.     vsyncCL();
  407.     vsetcurs(cp);
  408. }
  409.  
  410. /*
  411.  * Change operator.
  412.  *
  413.  * In a single line we mark the end of the changed area with '$'.
  414.  * On multiple whole lines, we clear the lines first.
  415.  * Across lines with both wcursor and wdot given, we delete
  416.  * and sync then append (but one operation for undo).
  417.  */
  418. vchange(c)
  419.     char c;
  420. {
  421.     register char *cp;
  422.     register int i, ind, cnt;
  423.     line *addr;
  424.  
  425.     if (wdot) {
  426.         /*
  427.          * Change/delete of lines or across line boundaries.
  428.          */
  429.         if ((cnt = xdw()) < 0)
  430.             return;
  431.         getDOT();
  432.         if (wcursor && cnt == 1) {
  433.             /*
  434.              * Not really.
  435.              */
  436.             wdot = 0;
  437.             if (c == 'd') {
  438.                 vdelete(c);
  439.                 return;
  440.             }
  441.             goto smallchange;
  442.         }
  443.         if (cursor && wcursor) {
  444.             /*
  445.              * Across line boundaries, but not
  446.              * necessarily whole lines.
  447.              * Construct what will be left.
  448.              */
  449.             *cursor = 0;
  450.             strcpy(genbuf, linebuf);
  451.             getline(*wdot);
  452.             if (strlen(genbuf) + strlen(wcursor) > LBSIZE - 2) {
  453.                 getDOT();
  454.                 beep();
  455.                 return;
  456.             }
  457.             strcat(genbuf, wcursor);
  458.             if (c == 'd' && *vpastwh(genbuf) == 0) {
  459.                 /*
  460.                  * Although this is a delete
  461.                  * spanning line boundaries, what
  462.                  * would be left is all white space,
  463.                  * so take it all away.
  464.                  */
  465.                 wcursor = 0;
  466.                 getDOT();
  467.                 op = 0;
  468.                 notpart(lastreg);
  469.                 notpart('1');
  470.                 vdelete(c);
  471.                 return;
  472.             }
  473.             ind = -1;
  474.         } else if (c == 'd' && wcursor == 0) {
  475.             vdelete(c);
  476.             return;
  477.         } else
  478. #ifdef LISPCODE
  479.             /*
  480.              * We are just substituting text for whole lines,
  481.              * so determine the first autoindent.
  482.              */
  483.             if (value(LISP) && value(AUTOINDENT))
  484.                 ind = lindent(dot);
  485.             else
  486. #endif
  487.                 ind = whitecnt(linebuf);
  488.         i = vcline >= 0 ? LINE(vcline) : WTOP;
  489.  
  490.         /*
  491.          * Delete the lines from the buffer,
  492.          * and remember how the partial stuff came about in
  493.          * case we are told to put.
  494.          */
  495.         addr = dot;
  496.         vremote(cnt, ex_delete, 0);
  497.         setpk();
  498.         notenam = "delete";
  499.         if (c != 'd')
  500.             notenam = "change";
  501.         /*
  502.          * If DEL[0] were nonzero, put would put it back
  503.          * rather than the deleted lines.
  504.          */
  505.         DEL[0] = 0;
  506.         if (cnt > 1)
  507.             killU();
  508.  
  509.         /*
  510.          * Now hack the screen image coordination.
  511.          */
  512.         vreplace(vcline, cnt, 0);
  513.         wdot = NOLINE;
  514.         ignore(noteit(0));
  515.         vcline--;
  516.         if (addr <= dol)
  517.             dot--;
  518.  
  519.         /*
  520.          * If this is a across line delete/change,
  521.          * cursor stays where it is; just splice together the pieces
  522.          * of the new line.  Otherwise generate a autoindent
  523.          * after a S command.
  524.          */
  525.         if (ind >= 0) {
  526.             *genindent(ind) = 0;
  527.             vdoappend(genbuf);
  528.         } else {
  529.             vmcurs = cursor;
  530.             strcLIN(genbuf);
  531.             vdoappend(linebuf);
  532.         }
  533.  
  534.         /*
  535.          * Indicate a change on hardcopies by
  536.          * erasing the current line.
  537.          */
  538.         if (c != 'd' && state != VISUAL && state != HARDOPEN) {
  539.             int oldhold = hold;
  540.  
  541.             hold |= HOLDAT, vclrlin(i, dot), hold = oldhold;
  542.         }
  543.  
  544.         /*
  545.          * Open the line (logically) on the screen, and 
  546.          * update the screen tail.  Unless we are really a delete
  547.          * go off and gather up inserted characters.
  548.          */
  549.         vcline++;
  550.         if (vcline < 0)
  551.             vcline = 0;
  552.         vopen(dot, i);
  553.         vsyncCL();
  554.         ignore(noteit(1));
  555.         if (c != 'd') {
  556.             if (ind >= 0) {
  557.                 cursor = linebuf;
  558.                 linebuf[0] = 0;
  559.                 vfixcurs();
  560.             } else {
  561.                 ind = 0;
  562.                 vcursat(cursor);
  563.             }
  564.             vappend('x', 1, ind);
  565.             return;
  566.         }
  567.         if (*cursor == 0 && cursor > linebuf)
  568.             cursor--;
  569.         vrepaint(cursor);
  570.         return;
  571.     }
  572.  
  573. smallchange:
  574.     /*
  575.      * The rest of this is just low level hacking on changes
  576.      * of small numbers of characters.
  577.      */
  578.     if (wcursor < linebuf)
  579.         wcursor = linebuf;
  580.     if (cursor == wcursor) {
  581.         beep();
  582.         return;
  583.     }
  584.     i = vdcMID();
  585.     cp = cursor;
  586.     if (state != HARDOPEN)
  587.         vfixcurs();
  588.  
  589.     /*
  590.      * Put out the \\'s indicating changed text in hardcopy,
  591.      * or mark the end of the change with $ if not hardcopy.
  592.      */
  593.     if (state == HARDOPEN) 
  594.         bleep(i, cp);
  595.     else {
  596.         vcursbef(wcursor);
  597.         ex_putchar('$');
  598.         i = cindent();
  599.     }
  600.  
  601.     /*
  602.      * Remember the deleted text for possible put,
  603.      * and then prepare and execute the input portion of the change.
  604.      */
  605.     cursor = cp;
  606.     setDEL();
  607.     CP(cursor, wcursor);
  608.     if (state != HARDOPEN) {
  609.         vcursaft(cursor - 1);
  610.         doomed = i - cindent();
  611.     } else {
  612. /*
  613.         sethard();
  614.         wcursor = cursor;
  615.         cursor = linebuf;
  616.         vgoto(outline, value(NUMBER) << 3);
  617.         vmove();
  618. */
  619.         doomed = 0;
  620.     }
  621.     prepapp();
  622.     vappend('c', 1, 0);
  623. }
  624.  
  625. /*
  626.  * Open new lines.
  627.  *
  628.  * Tricky thing here is slowopen.  This causes display updating
  629.  * to be held off so that 300 baud dumb terminals don't lose badly.
  630.  * This also suppressed counts, which otherwise say how many blank
  631.  * space to open up.  Counts are also suppressed on intelligent terminals.
  632.  * Actually counts are obsoleted, since if your terminal is slow
  633.  * you are better off with slowopen.
  634.  */
  635. voOpen(c, cnt)
  636.     int c;    /* mjm: char --> int */
  637.     register int cnt;
  638. {
  639.     register int ind = 0, i;
  640.     short oldhold = hold;
  641. #ifdef    SIGWINCH
  642.     int oldmask;
  643. #endif
  644.  
  645.     if (value(SLOWOPEN) || value(REDRAW) && AL && DL)
  646.         cnt = 1;
  647. #ifdef    SIGWINCH
  648.     oldmask = sigblock(sigmask(SIGWINCH));
  649. #endif
  650.     vsave();
  651.     setLAST();
  652.     if (value(AUTOINDENT))
  653.         ind = whitecnt(linebuf);
  654.     if (c == 'O') {
  655.         vcline--;
  656.         dot--;
  657.         if (dot > zero)
  658.             getDOT();
  659.     }
  660.     if (value(AUTOINDENT)) {
  661. #ifdef LISPCODE
  662.         if (value(LISP))
  663.             ind = lindent(dot + 1);
  664. #endif
  665.     }
  666.     killU();
  667.     prepapp();
  668.     if (FIXUNDO)
  669.         vundkind = VMANY;
  670.     if (state != VISUAL)
  671.         c = WBOT + 1;
  672.     else {
  673.         c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline);
  674.         if (c < ex_ZERO)
  675.             c = ex_ZERO;
  676.         i = LINE(vcline + 1) - c;
  677.         if (i < cnt && c <= WBOT && (!AL || !DL))
  678.             vinslin(c, cnt - i, vcline);
  679.     }
  680.     *genindent(ind) = 0;
  681.     vdoappend(genbuf);
  682.     vcline++;
  683.     oldhold = hold;
  684.     hold |= HOLDROL;
  685.     vopen(dot, c);
  686.     hold = oldhold;
  687.     if (value(SLOWOPEN))
  688.         /*
  689.          * Oh, so lazy!
  690.          */
  691.         vscrap();
  692.     else
  693.         vsync1(LINE(vcline));
  694.     cursor = linebuf;
  695.     linebuf[0] = 0;
  696.     vappend('o', 1, ind);
  697. #ifdef    SIGWINCH
  698.     (void)sigsetmask(oldmask);
  699. #endif
  700. }
  701.  
  702. /*
  703.  * > < and = shift operators.
  704.  *
  705.  * Note that =, which aligns lisp, is just a ragged sort of shift,
  706.  * since it never distributes text between lines.
  707.  */
  708. char    vshnam[2] = { 'x', 0 };
  709.  
  710. vshftop()
  711. {
  712.     register line *addr;
  713.     register int cnt;
  714.  
  715.     if ((cnt = xdw()) < 0)
  716.         return;
  717.     addr = dot;
  718.     vremote(cnt, vshift, 0);
  719.     vshnam[0] = op;
  720.     notenam = vshnam;
  721.     dot = addr;
  722.     vreplace(vcline, cnt, cnt);
  723.     if (state == HARDOPEN)
  724.         vcnt = 0;
  725.     vrepaint(NOSTR);
  726. }
  727.  
  728. /*
  729.  * !.
  730.  *
  731.  * Filter portions of the buffer through unix commands.
  732.  */
  733. vfilter()
  734. {
  735.     register line *addr;
  736.     register int cnt;
  737.     char *oglobp;
  738.     short d;
  739.  
  740.     if ((cnt = xdw()) < 0)
  741.         return;
  742.     if (vglobp)
  743.         vglobp = uxb;
  744.     if (readecho('!'))
  745.         return;
  746.     oglobp = globp; globp = genbuf + 1;
  747.     d = peekc; ungetchar(0);
  748.     CATCH
  749.         fixech();
  750.         unix0(0);
  751.     ONERR
  752.         splitw = 0;
  753.         ungetchar(d);
  754.         vrepaint(cursor);
  755.         globp = oglobp;
  756.         return;
  757.     ENDCATCH
  758.     ungetchar(d); globp = oglobp;
  759.     addr = dot;
  760.     CATCH
  761.         vgoto(WECHO, 0); flusho();
  762.         vremote(cnt, filter, 2);
  763.     ONERR
  764.         vdirty(0, LINES);
  765.     ENDCATCH
  766.     if (dot == zero && dol > zero)
  767.         dot = one;
  768.     splitw = 0;
  769.     notenam = "";
  770.     /*
  771.      * BUG: we shouldn't be depending on what undap2 and undap1 are,
  772.      * since we may be inside a macro.  What's really wanted is the
  773.      * number of lines we read from the filter.  However, the mistake
  774.      * will be an overestimate so it only results in extra work,
  775.      * it shouldn't cause any real screwups.
  776.      */
  777.     vreplace(vcline, cnt, undap2 - undap1);
  778.     dot = addr;
  779.     if (dot > dol) {
  780.         dot--;
  781.         vcline--;
  782.     }
  783.     vrepaint(NOSTR);
  784. }
  785.  
  786. /*
  787.  * Xdw exchanges dot and wdot if appropriate and also checks
  788.  * that wdot is reasonable.  Its name comes from
  789.  *    xchange dotand wdot
  790.  */
  791. xdw()
  792. {
  793.     register char *cp;
  794.     register int cnt;
  795. /*
  796.     register int notp = 0;
  797.  */
  798.  
  799.     if (wdot == NOLINE || wdot < one || wdot > dol) {
  800.         beep();
  801.         return (-1);
  802.     }
  803.     vsave();
  804.     setLAST();
  805.     if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) {
  806.         register line *addr;
  807.  
  808.         vcline -= dot - wdot;
  809.         addr = dot; dot = wdot; wdot = addr;
  810.         cp = cursor; cursor = wcursor; wcursor = cp;
  811.     }
  812.     /*
  813.      * If a region is specified but wcursor is at the begining
  814.      * of the last line, then we move it to be the end of the
  815.      * previous line (actually off the end).
  816.      */
  817.     if (cursor && wcursor == linebuf && wdot > dot) {
  818.         wdot--;
  819.         getDOT();
  820.         if (vpastwh(linebuf) >= cursor)
  821.             wcursor = 0;
  822.         else {
  823.             getline(*wdot);
  824.             wcursor = strend(linebuf);
  825.             getDOT();
  826.         }
  827.         /*
  828.          * Should prepare in caller for possible dot == wdot.
  829.          */
  830.     }
  831.     cnt = wdot - dot + 1;
  832.     if (vreg) {
  833.         vremote(cnt, YANKreg, vreg);
  834. /*
  835.         if (notp)
  836.             notpart(vreg);
  837.  */
  838.     }
  839.  
  840.     /*
  841.      * Kill buffer code.  If delete operator is c or d, then save
  842.      * the region in numbered buffers.
  843.      *
  844.      * BUG:            This may be somewhat inefficient due
  845.      *            to the way named buffer are implemented,
  846.      *            necessitating some optimization.
  847.      */
  848.     vreg = 0;
  849.     if (any(op, "cd")) {
  850.         vremote(cnt, YANKreg, '1');
  851. /*
  852.         if (notp)
  853.             notpart('1');
  854.  */
  855.     }
  856.     return (cnt);
  857. }
  858.  
  859. /*
  860.  * Routine for vremote to call to implement shifts.
  861.  */
  862. vshift()
  863. {
  864.  
  865.     shift(op, 1);
  866. }
  867.  
  868. /*
  869.  * Replace a single character with the next input character.
  870.  * A funny kind of insert.
  871.  */
  872. vrep(cnt)
  873.     register int cnt;
  874. {
  875.     register int i, c;
  876.  
  877.     if (cnt > strlen(cursor)) {
  878.         beep();
  879.         return;
  880.     }
  881.     i = column(cursor + cnt - 1);
  882.     vcursat(cursor);
  883.     doomed = i - cindent();
  884.     if (!vglobp) {
  885.         c = getesc();
  886.         if (c == 0) {
  887.             vfixcurs();
  888.             return;
  889.         }
  890.         ungetkey(c);
  891.     }
  892.     CP(vutmp, linebuf);
  893.     if (FIXUNDO)
  894.         vundkind = VCHNG;
  895.     wcursor = cursor + cnt;
  896.     vUD1 = cursor; vUD2 = wcursor;
  897.     CP(cursor, wcursor);
  898.     prepapp();
  899.     vappend('r', cnt, 0);
  900.     *lastcp++ = INS[0];
  901.     setLAST();
  902. }
  903.  
  904. /*
  905.  * Yank.
  906.  *
  907.  * Yanking to string registers occurs for free (essentially)
  908.  * in the routine xdw().
  909.  */
  910. vyankit()
  911. {
  912.     register int cnt;
  913.  
  914.     if (wdot) {
  915.         if ((cnt = xdw()) < 0)
  916.             return;
  917.         vremote(cnt, yank, 0);
  918.         setpk();
  919.         notenam = "yank";
  920.         if (FIXUNDO)
  921.             vundkind = VNONE;
  922.         DEL[0] = 0;
  923.         wdot = NOLINE;
  924.         if (notecnt <= vcnt - vcline && notecnt < value(REPORT))
  925.             notecnt = 0;
  926.         vrepaint(cursor);
  927.         return;
  928.     }
  929.     takeout(DEL);
  930. }
  931.  
  932. /*
  933.  * Set pkill variables so a put can
  934.  * know how to put back partial text.
  935.  * This is necessary because undo needs the complete
  936.  * line images to be saved, while a put wants to trim
  937.  * the first and last lines.  The compromise
  938.  * is for put to be more clever.
  939.  */
  940. setpk()
  941. {
  942.  
  943.     if (wcursor) {
  944.         pkill[0] = cursor;
  945.         pkill[1] = wcursor;
  946.     }
  947. }
  948.